package me.leiusual.sharing.api.interceptor

import android.os.Build
import com.google.gson.JsonObject
import me.leiusual.sharing.api.exception.BusinessLogicException
import me.leiusual.sharing.api.exception.ContentProtocolException
import me.leiusual.sharing.pref.Store
import me.leiusual.sharing.pref.Token
import me.leiusual.sharing.util.extension.gson
import okhttp3.Interceptor
import okhttp3.MediaType
import okhttp3.Response
import okhttp3.ResponseBody
import java.io.IOException
import java.nio.charset.Charset
import javax.inject.Inject

/**
 * author: leiusual
 * create on: 2018/10/19
 * description:
 */
class InterceptorImpl @Inject constructor(
    private val token: Token,
    private val store: Store
) : Interceptor {

  companion object {
    private const val CODE = "code"
    private const val MESSAGE = "message"
    private const val DATA = "data"

    // 忽略自定义协议解析的接口
    private val ignoreProtocolPaths = listOf(
        "/s/oauth/token",
        "/s/me",
        "/api/logistics"
    )

    private val mediaType = MediaType.parse("application/json; charset=utf-8")
  }

  override fun intercept(chain: Interceptor.Chain): Response {
    val originalRequest = chain.request()

    val newRequest = originalRequest.newBuilder()
        .addHeader("Authorization", "Bearer ${token.accessToken}")
        .header("User-Agent", "Android ${Build.VERSION.RELEASE}")
        .header("bindingStoreId", store.bindingStoreId.toString())
        .header("currentStoreId", store.currentStoreId.toString())
        .build()

    val originalResponse = try {
      chain.proceed(newRequest)
    } catch (e: Exception) {
      throw IOException("服务器正在升级，请稍后", e)
    }

    // http code
    when (originalResponse.code()) {
      400 -> throw IOException("提交数据异常")
      401 -> {
        token.clear()
        throw IOException("登录失效了，请重新登录")
      }
    }

    // filter url
    val encodedPath = originalResponse.request().url().encodedPath()

    // handle protocol
    if (ignoreProtocolPaths.find { path -> encodedPath.startsWith(path) } == null) {
      originalResponse.body()?.let {

        // parse json
        val source = it.source()
        source.request(Long.MAX_VALUE)
        val buffer = source.buffer()
        val bodyString = buffer.clone().readString(Charset.defaultCharset())

        val json = try {
          gson.fromJson(bodyString, JsonObject::class.java)
        } catch (e: Exception) {
          throw ContentProtocolException(e)
        }

        val code = json.get(CODE).asInt
        if (code != 0) {
          throw BusinessLogicException(json.get(MESSAGE).asString)
        }

        // handle data
        var data = json.get(DATA).toString()
        if (!data.startsWith("{") && !data.startsWith("[")) {
          data = """{"data":$data}"""
        }
        return originalResponse.newBuilder()
            .body(ResponseBody.create(mediaType, data))
            .build()
      }
    }

    return originalResponse
  }
}